package utils;

import java.io.Serializable;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.InetAddress;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;

public class IpUtil implements Serializable {

	private static final long serialVersionUID = 1L;

	public static Boolean isIp(String ip) {
		if (isIpv4(ip) || isIpv6(ip)) {
			return true;
		}
		return false;
	}

	public static Boolean isIpv4(String ip) {
		if (Pattern.compile("^(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])(\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])){3}$").matcher(ip).matches()) {
			return true;
		}
		return false;
	}

	public static Boolean isIpv6(String ip) {
		if (Pattern
				.compile(
						"^((([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){1,7}:)|(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){5}(:[0-9A-Fa-f]{1,4}){1,2})|(([0-9A-Fa-f]{1,4}:){4}(:[0-9A-Fa-f]{1,4}){1,3})|(([0-9A-Fa-f]{1,4}:){3}(:[0-9A-Fa-f]{1,4}){1,4})|(([0-9A-Fa-f]{1,4}:){2}(:[0-9A-Fa-f]{1,4}){1,5})|([0-9A-Fa-f]{1,4}:(:[0-9A-Fa-f]{1,4}){1,6})|(:(:[0-9A-Fa-f]{1,4}){1,7})|(([0-9A-Fa-f]{1,4}:){6}(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])(\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])){3})|(([0-9A-Fa-f]{1,4}:){5}:(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])(\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])){3})|(([0-9A-Fa-f]{1,4}:){4}(:[0-9A-Fa-f]{1,4}){0,1}:(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])(\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])){3})|(([0-9A-Fa-f]{1,4}:){3}(:[0-9A-Fa-f]{1,4}){0,2}:(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])(\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])){3})|(([0-9A-Fa-f]{1,4}:){2}(:[0-9A-Fa-f]{1,4}){0,3}:(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])(\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])){3})|([0-9A-Fa-f]{1,4}:(:[0-9A-Fa-f]{1,4}){0,4}:(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])(\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])){3})|(:(:[0-9A-Fa-f]{1,4}){0,5}:(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])(\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])){3}))$")
				.matcher(ip).matches()) {
			return true;
		}
		return false;
	}

	public static BigDecimal ip2number(String ip) {
		if (isIpv4(ip)) {
			return ipv42number(ip);
		}
		if (isIpv6(ip)) {
			return ipv62number(ip);
		}
		return new BigDecimal(1);
	}

	/** 将IPv4字符串转化为对应的长整型整数 */
	public static BigDecimal ipv42number(String ipv4) {
		try {
			String[] p4 = ipv4.split("\\.");
			long ipInt = 0;
			long part = Long.valueOf(p4[0]);
			ipInt = ipInt | (part << 24);
			part = Long.valueOf(p4[1]);
			ipInt = ipInt | (part << 16);
			part = Long.valueOf(p4[2]);
			ipInt = ipInt | (part << 8);
			part = Long.valueOf(p4[3]);
			ipInt = ipInt | (part);
			return new BigDecimal(ipInt);
		} catch (Exception e) {
			return new BigDecimal(1);
		}
	}

	/** 将IP地址长整型数值转化为IPv4字符串 */
	public static String number2ipv4(long ipNumber) {
		String ipStr = String.valueOf((ipNumber & 0xff000000) >> 24);
		ipStr += "." + ((ipNumber & 0xff0000) >> 16);
		ipStr += "." + ((ipNumber & 0xff00) >> 8);
		ipStr += "." + (ipNumber & 0xff);
		return ipStr;
	}

	/** 将IP地址长整型数值转化为IPv6字符串 */
	public static BigDecimal ipv62number(String ipv6) {
		byte[] bytes = null;
		try {
			bytes = InetAddress.getByName(ipv6).getAddress();
			return new BigDecimal(new BigInteger(1, bytes));
		} catch (Exception e) {
			return new BigDecimal(new BigInteger(new Integer(1).toString()));
		}
	}

	/** 将IPv6字符串转化为对应的长整型整数 */
	public static String number2ipv6(BigInteger ipNumber) {
		String ipString = "";
		BigInteger a = new BigInteger("FFFF", 16);
		for (int i = 0; i < 8; i++) {
			ipString = ipNumber.and(a).toString(16) + ":" + ipString;
			ipNumber = ipNumber.shiftRight(16);
		}
		return ipString.substring(0, ipString.length() - 1);
	}

	/** 根据掩码计算ip起始点,兼容ipv4和ipv6 */
	public static String calcStart(String ipAddress, int maskLength) {
		InetAddress inetAddress = null;
		try {
			inetAddress = InetAddress.getByName(ipAddress);
			ByteBuffer maskBuffer;
			int targetSize;
			if (inetAddress.getAddress().length == 4) {
				maskBuffer = ByteBuffer.allocate(4).putInt(-1);
				targetSize = 4;
			} else {
				maskBuffer = ByteBuffer.allocate(16).putLong(-1L).putLong(-1L);
				targetSize = 16;
			}
			BigInteger mask = (new BigInteger(1, maskBuffer.array())).not().shiftRight(maskLength);
			ByteBuffer buffer = ByteBuffer.wrap(inetAddress.getAddress());
			BigInteger ipVal = new BigInteger(1, buffer.array());
			BigInteger startIp = ipVal.and(mask);

			int counter = 0;
			List<Byte> newArr = new ArrayList<Byte>();
			while (counter < targetSize && (startIp.toByteArray().length - 1 - counter >= 0)) {
				newArr.add(0, startIp.toByteArray()[startIp.toByteArray().length - 1 - counter]);
				counter++;
			}
			int size = newArr.size();
			for (int i = 0; i < (targetSize - size); i++) {
				newArr.add(0, (byte) 0);
			}
			byte[] ret = new byte[newArr.size()];
			for (int i = 0; i < newArr.size(); i++) {
				ret[i] = newArr.get(i);
			}
			return InetAddress.getByAddress(ret).getHostAddress();
		} catch (Exception e) {
			return ipAddress;
		}
	}

	/** 根据掩码计算ip结束点,兼容ipv4和ipv6 */
	public static String calcEnd(String ipAddress, int maskLength) {
		InetAddress inetAddress = null;
		try {
			inetAddress = InetAddress.getByName(ipAddress);
			ByteBuffer maskBuffer;
			int targetSize;
			if (inetAddress.getAddress().length == 4) {
				maskBuffer = ByteBuffer.allocate(4).putInt(-1);
				targetSize = 4;
			} else {
				maskBuffer = ByteBuffer.allocate(16).putLong(-1L).putLong(-1L);
				targetSize = 16;
			}
			BigInteger mask = (new BigInteger(1, maskBuffer.array())).not().shiftRight(maskLength);
			ByteBuffer buffer = ByteBuffer.wrap(inetAddress.getAddress());
			BigInteger ipVal = new BigInteger(1, buffer.array());
			BigInteger endIp = ipVal.and(mask).add(mask.not());

			int counter = 0;
			List<Byte> newArr = new ArrayList<Byte>();
			while (counter < targetSize && (endIp.toByteArray().length - 1 - counter >= 0)) {
				newArr.add(0, endIp.toByteArray()[endIp.toByteArray().length - 1 - counter]);
				counter++;
			}
			int size = newArr.size();
			for (int i = 0; i < (targetSize - size); i++) {
				newArr.add(0, (byte) 0);
			}
			byte[] ret = new byte[newArr.size()];
			for (int i = 0; i < newArr.size(); i++) {
				ret[i] = newArr.get(i);
			}
			return InetAddress.getByAddress(ret).getHostAddress();
		} catch (Exception e) {
			return ipAddress;
		}
	}

	public static void main(String[] args) {
		
		// System.out.println(isIpv6("2001:0DB8:0000:0023:0008:0800:200C:417A"));
		// System.out.println(isIpv6("2001:DB8:0:23:8:800:200C:417A"));
		// System.out.println(isIpv6("2001:DB8:0:23:8:800:192.1.0.0"));
		// System.out.println(isIpv6("2001:DB8:0::800:192.1.0.0"));
		// System.out.println(isIpv6("2001:DB8:0:23::192.1.0.0"));
		// System.out.println(isIpv6("::192.1.0.0"));
		// System.out.println(isIpv6("1:af::3"));
		// System.out.println(isIpv6("1:af::"));
		// System.out.println(isIpv6("::1:af:0"));
		// System.out.println(isIpv6("::0"));
		// System.out.println("---------------------");
		// System.out.println(isIpv6("+2001:0DB8:0000:0023:0008:0800:200C:417A"));
		// System.out.println(isIpv6("2001:0DB8:0z00:0023:0008:0800:200C:417A"));
		// System.out.println(isIpv6("2001:DB8:0:23:800::192.1.0.0.1"));
		// System.out.println(isIpv6("2001:DB8::23::800:192.1.0.0"));
		// System.out.println(isIpv6(":::"));
		// System.out.println(isIpv6("1:::2"));
		//
		// System.out.println("---------------------");
		// System.out.println(isIpv4("1.1.0.1"));
		// System.out.println(isIpv4("123.1.0.19"));
		// System.out.println(isIpv4("255.255.255.255"));
		// System.out.println(isIpv4("0.0.0.0"));
		// System.out.println("---------------------");
		// System.out.println(isIpv4("-1.1.0.1"));
		// System.out.println(isIpv4("1.1b.0.1"));
		// System.out.println(isIpv4("1.01.0.1"));
		// System.out.println(isIpv4("1.1.300.1"));
		// System.out.println(isIpv4("1.1..1"));
		//
		// System.out.println(IpUtil.ipv62number("FFFF::E3F1:2345:1111"));
		// System.out.println(IpUtil.number2ipv6(new
		// BigInteger("340277174624079928635746327560257343761")));
		// System.out.println("===========================");
		// for (int i = 0; i < 10; i++) {
		//
		// BigInteger b = new
		// BigInteger(NumberUtil.random(IpUtil.ipv62number("FFFF::E3F1:2345:1111").toBigInteger(),
		// IpUtil.ipv62number("FFFF::E3F1:2345:68e9").toBigInteger()) + "");
		// System.out.println(b);
		// System.out.println(IpUtil.number2ipv6(b));
		// }
		// System.out.println("===========================");
		// System.out.println(IpUtil.ipv62number("FFFF::E3F1:2345:68e9"));
		// System.out.println(IpUtil.number2ipv6(new
		// BigInteger("340277174624079928635746327560257366249")));
		//
		// System.out.println("===========================");
		// System.out.println("===========================");
		// System.out.println("===========================");
		// System.out.println("===========================");
		// System.out.println("===========================");
		//
		// System.out.println(IpUtil.ipv42number("127.0.0.1"));
		// System.out.println(IpUtil.number2ipv4(new Long("2130706433")));
		// System.out.println("===========================");
		// for (int i = 0; i < 10; i++) {
		//
		// long b =
		// NumberUtil.random(IpUtil.ipv42number("127.0.0.1").longValue(),
		// IpUtil.ipv42number("127.0.2.1").longValue());
		// System.out.println(b);
		// System.out.println(IpUtil.number2ipv4(b));
		// }
		// System.out.println("===========================");
		// System.out.println(IpUtil.ipv42number("127.0.2.1"));
		// System.out.println(IpUtil.number2ipv4(new Long("2130706945")));
		//
		// long s = ipv42number("127.0.0.1").longValue();
		// System.out.println(s);
		// String b = number2ipv4(s);
		// System.out.println(b);
		//
		// BigInteger a = ipv62number("FFFF::E3F1:2345:68e9").toBigInteger();
		// System.out.println(a);
		// String c = number2ipv6(a);
		// System.out.println(c);
		//
		// System.out.println("===================");
		// String start = calcStart("::E3F1:2345:68e9", 101);
		// String end = calcEnd("::E3F1:2345:68e9", 101);
		// // String start=calcStart("10.22.1.0", 24);
		// // String end=calcEnd("10.22.1.0", 24);
		// System.out.println(start);
		// System.out.println(end);
		//
		// System.out.println("===================");
		//
		// BigInteger ss = ipv62number(start).toBigInteger();
		// BigInteger ee = ipv62number(end).toBigInteger();
		//
		// for (int i = 0; i < 10; i++) {
		// BigInteger rand = NumberUtil.random(ss, ee);
		// String bb = number2ipv6(rand);
		// System.out.println(bb);
		// }

	}
}
